#include <timer.h>
#include <clock.h>

#ifdef USE_WORK_QUEUE
#include <units/work_queue.h>
#endif

static LIST(timer_list);

static void __timer_init(struct timer *timer,
				  const char *name,
				  void (*timeout_func) (void *args),
				  void *args,
				  ubase_t time,
				  uint8_t flag)
{
	timer->init_tick = time;
	timer->timeout_func = timeout_func;
	timer->timeout_tick = 0;
	timer->args = args;
	timer->flag = flag;

	timer->parent.type = CLASS_TYPE_DEVICE;

	object_init(&timer->parent, name);
}

/* 初始化定时器 */
err_t timer_init(struct timer *timer,
				  const char *name,
				  void (*timeout_func) (void *args),
				  void *args,
				  ubase_t time,
				  uint8_t flag)
{
	if (timer == NULL)
		return -EINVAL;

	__timer_init(timer,
				 name,
				 timeout_func,
				 args,
				 time,
				 flag);

	return 0;
}

/* 创建一个定时器 */
struct timer *timer_create(const char *name,
				  void (*timeout_func) (void *args),
				  void *args,
				  ubase_t time,
				  uint8_t flag)
{
	struct timer *timer;

	timer = (struct timer *)malloc(sizeof(struct timer));

	if (timer == NULL)
		return NULL;

	__timer_init(timer,
				 name,
				 timeout_func,
				 args,
				 time,
				 flag);

	return timer;
}

/* 删除一个定时器 */
err_t timer_del(struct timer *timer)
{
	err_t ret = 0;

	ret = timer_stop(timer);
	if (ret < 0)
		return ret;

	object_deinit(&timer->parent);

	free(timer);

	return ret;
}

/* 启动一个定时器 */
err_t timer_start(struct timer *timer)
{
	register base_t level;
	struct timer *last_timer, *tmp_timer;

	if (timer->flag & TIMER_FLAG_START)
		return -EBUSY;

	level = interrupt_disable();

	/* 计算定时器溢出时间 */
	timer->timeout_tick = get_tick() + timer->init_tick;

	/* 如果没有定时器则直接将这个定时器插入到队尾 */
	if (list_empty(&timer_list)) {
		list_add_tail(&timer->list, &timer_list);
		goto __exit;
	}

	/* 获取溢出时间最长的定时器 */
	last_timer = list_last_entry(&timer_list, struct timer, list);

	/* 如果当前定时器定时长度已经比最大的定时器长，则插入到队尾 */
	if (last_timer->timeout_tick <= timer->timeout_tick) {
		list_add_tail(&timer->list, &timer_list);
		goto __exit;
	}

	/* 查找定时器需要插入到队列中的位置 */
	list_for_each_entry(tmp_timer, &timer_list, list) {
		if (tmp_timer->timeout_tick >= timer->timeout_tick) {
			list_add_tail(&timer->list, &tmp_timer->list);
			goto __exit;
		}
	}

__exit:

	/* 将定时开始标志位置位 */
	timer->flag |= TIMER_FLAG_START;

	interrupt_enable(level);

	return 0;
}

/* 停止一个定时器 */
err_t timer_stop(struct timer *timer)
{
	/* 从定时器列表中移除 */
	list_del(&timer->list);
	/* 将定时开始标志位清除 */
	timer->flag &= ~TIMER_FLAG_START;

	return 0;
}

/* 定时器控制函数 */
err_t timer_control(struct timer *timer, uint8_t cmd, void *args)
{
	err_t ret = 0;

	switch (cmd) {
	case TIMER_CMD_SET_TIME:
	{
		ubase_t tick = *((ubase_t *)args);

		timer->init_tick = tick;
		break;
	}
	default:
	{
		ret = -EINVAL;
		break;
	}
	};

	return ret;
}

/* 检查定时器是否超时 */
void timer_timeout_check(void)
{
	register base_t level;
	struct timer *timer;
	ubase_t current_tick = get_tick();

	level = interrupt_disable();

	timer = list_first_entry(&timer_list, struct timer, list);

	if (current_tick >= timer->timeout_tick) {
		/* 从定时器列表中移除 */
		list_del(&timer->list);

		timer->timeout_func(timer->args);

		timer->flag |= TIMER_FLAG_TIMEOUT;
		/* 将定时开始标志位清除 */
		timer->flag &= ~TIMER_FLAG_START;
	}

	interrupt_enable(level);
}

